<?php

declare(strict_types=1);

namespace app;

use think\App;
use think\exception\ValidateException;
use think\Validate;
use think\Facade\Session;

/**
 * 控制器基础类
 */
abstract class BaseController
{
    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {
        $this->app     = $app;
        $this->request = $this->app->request;

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
    }

    /**
     * 验证数据
     * @access protected
     * @param  array        $data     数据
     * @param  string|array $validate 验证器名或者验证规则数组
     * @param  array        $message  提示信息
     * @param  bool         $batch    是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                [$validate, $scene] = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v     = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        return $v->failException(true)->check($data);
    }

    /**
     * 设置一次性 Session 消息
     * 
     * @param string $message 要显示的消息内容。
     * @param string $type    消息类型（例如 'success', 'error', 'warning', 'info'）。
     *
     * @return void
     */
    protected function flash(string $message, string $type = 'info'): void
    {
        $flashKey = 'toast'; // 定义存储 Flash 数据的主键

        $toastData = [
            'message' => $message,
            'type'    => $type
        ];

        $existingFlashData = Session::get($flashKey, []);
        $mergedData        = $this->arrayMergeRecursiveDistinct($existingFlashData, $toastData);

        Session::set($flashKey, $mergedData);
    }

    /**
     * 递归地合并两个数组，对于相同键的值，第二个数组中的值会覆盖第一个数组中的值。
     * 如果两个值都是数组，则递归合并它们。
     *
     * 这与 PHP 内置的 array_merge_recursive 不同，后者会将具有相同键的多个值合并成一个数组。
     * 本函数的行为更类似于 array_merge，但在遇到嵌套数组时会递归处理。
     *
     * @param array $array1 第一个数组。
     * @param array $array2 第二个数组，其值将覆盖第一个数组中的同名键值。
     *
     * @return array 合并后的新数组。
     */
    protected function arrayMergeRecursiveDistinct(array $array1, array $array2): array
    {
        $merged = $array1;

        foreach ($array2 as $key => &$value) {
            if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
                $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
            } else {
                $merged[$key] = $value; // 覆盖或新增
            }
        }

        return $merged;
    }
}
